package maiaclient;

import data.Building;
import data.BuildingType;
import data.Resource;
import data.TownCenterBuildingType;
import data.Village;
import data.User;
import data.logic.BuildingSquareTypeFactory;
import data.logic.BuildingSquareType;
import data.logic.Square;
import data.logic.VillageSquareType;
import gui.MaiaWorld;
import java.awt.Point;
import java.io.IOException;
import java.util.Vector;
import maiaclient.interfaces.IBuildingListener;
import maiaclient.interfaces.IBuildingTypeListener;
import maiaclient.interfaces.IChatListener;
import maiaclient.interfaces.IFriendListener;
import maiaclient.interfaces.IResourceListener;
import maiaclient.interfaces.IUserListener;
import maiaclient.interfaces.IVillageListener;
import network.MaiaClient;

/**
 *
 * @author groep 11
 * @date 2007-2008
 */
public class Maia {

    private String serverIP;
    private int serverPort;
    private MaiaClient maiaclient;
    private MaiaWorld maiaworld;
    private User user;
    private Village village;
    private Vector<IChatListener> chatListeners;
    private Vector<IVillageListener> villageListeners;
    private Vector<IUserListener> userListeners;
    private Vector<IFriendListener> friendListeners;
    private Vector<IResourceListener> resourceListeners;
    private Vector<IBuildingListener> buildingListeners;
    private Vector<IBuildingTypeListener> buildingTypeListeners;
    private int villageLevel;

    public Maia(String serverIP, int serverPort) {
        setServerIP(serverIP);
        setServerPort(serverPort);

        maiaclient = new MaiaClient(this);

        // Initialize listener collections
        chatListeners = new Vector<IChatListener>();
        villageListeners = new Vector<IVillageListener>();
        userListeners = new Vector<IUserListener>();
        friendListeners = new Vector<IFriendListener>();
        resourceListeners = new Vector<IResourceListener>();
        buildingListeners = new Vector<IBuildingListener>();
        buildingTypeListeners = new Vector<IBuildingTypeListener>();
    }

    // <editor-fold desc="GETTERS/SETTERS" defaultstate="collapsed">
    public String getServerIP() {
        return serverIP;
    }

    public void setServerIP(String serverIP) {
        this.serverIP = serverIP;
    }

    public int getServerPort() {
        return serverPort;
    }

    public void setServerPort(int serverPort) {
        this.serverPort = serverPort;
    }

    public MaiaClient getMaiaClient() {
        return this.maiaclient;
    }

    public User getUser() {
        return this.user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public MaiaWorld getMaiaworld() {
        return maiaworld;
    }

    public void setMaiaWorld(MaiaWorld maiaworld) {
        this.maiaworld = maiaworld;
    }

    // </editor-fold>
    // <editor-fold desc="CHAT" defaultstate="collapsed">
    /**
     * Adds a listener to the chat listeners.
     * @param listener
     */
    public void addChatListener(IChatListener listener) {
        chatListeners.add(listener);
    }

    /**
     * Removes a listener from the chat listeners.
     * @param listener
     */
    public void removeChatListener(IChatListener listener) {
        chatListeners.remove(listener);
    }

    /**
     * Updates the chat listeners' online clients list
     */
    public void updateChatListeners() {
        for (IChatListener listener : chatListeners) {
            listener.updateAllOnlineUsers();
        }
    }

    /**
     * Sends chat messages to the chat listeners.
     * There are 3 types of messages: 0 = all online users, 1 = tribe members, 2 = friends
     * @param message
     * @param type
     */
    public void showChatMessage(String message, int type) {
        for (IChatListener listener : chatListeners) {
            listener.showChatmessage(message, type);
        }
    }

    // </editor-fold>
    /////////////////// Villages Listeners /////////////
    /**
     * Adds a listener to the village listeners.
     * @param listener
     */
    public void addVillageListener(IVillageListener listener) {
        villageListeners.add(listener);
    }

    /**
     * Removes a listener from the village listeners.
     * @param listener
     */
    public void removeVillageListener(IVillageListener listener) {
        villageListeners.remove(listener);
    }

    /**
     * Sends chat messages to the chat listeners.
     * There are 3 types of messages: 0 = all online users, 1 = tribe members, 2 = friends
     * @param message
     * @param type
     */
    public void showVillages(Vector<Village> villages) {

        Vector<Square> sqVillages = new Vector<Square>();
        for (Village localVillage : villages) {
            Square vv = new Square(new VillageSquareType(localVillage));
            vv.setPosition(new Point(localVillage.getLocationX(), localVillage.getLocationY()));
            sqVillages.add(vv);
        }
        for (IVillageListener listener : villageListeners) {
            listener.updateVillages(sqVillages);
        }
    }

    public void requestInitializedVillages() throws IOException, ClassNotFoundException {
        maiaclient.requestInitializedVillages();
    }
    /////////////////// Villages listeners  /////////////
    /////////////////// User Listeners      //////////////
    /**
     * Adds a listener to the User listeners.
     * @param listener
     */
    public void addUserListener(IUserListener listener) {
        userListeners.add(listener);
    }

    /**
     * Removes a listener from the User listeners.
     * @param listener
     */
    public void removeUserListener(IUserListener listener) {
        userListeners.remove(listener);
    }

    public void showUserInfo(User user) {

        for (IUserListener listener : userListeners) {
            listener.updateUser(user);
        }
    }

    public void requestUserByUserId(int userID) throws IOException {
        maiaclient.requestUserByUserid(userID);
    }

    /////////////////// User Listeners      //////////////
    /////////////////// Friend Listeners   //////////////
    public void addFriendListener(IFriendListener listener) {

        friendListeners.add(listener);

    }

    public void removeFriendListener(IFriendListener listener) {
        friendListeners.remove(listener);
    }

    public void showFriends(Vector<User> friends) {

        for (IFriendListener listener : friendListeners) {
            listener.updateFriends(friends);
        }
    }

    public void requestFriends() throws IOException {
        maiaclient.requestFriends(user.getUserId());
    }
    /////////////////// Friend Listeners  //////////////
    //////////////////  Resource Listeners ////////////
    //requestResources 
    public void addResourceListener(IResourceListener listener) {

        resourceListeners.add(listener);
    }

    public void removeResourceListener(IResourceListener listener) {
        resourceListeners.remove(listener);
    }

    public void updateResources(Vector<Resource> resources) {

        for (IResourceListener listener : resourceListeners) {
            listener.updateResources(resources);
        }
    }

    public void requestResources() throws IOException {
        maiaclient.requestResources();
    }
    //////////////////  Resource Listeners ////////////
    /////////////////   Building Listeners ///////////
    public void addBuildingListener(IBuildingListener listener) {

        buildingListeners.add(listener);
    }

    public void removeBuildingListener(IBuildingListener listener) {
        buildingListeners.remove(listener);
    }

    public void requestBuildings() throws IOException {
        maiaclient.requestBuildings();
    }

    public void updateBuildings(Vector<Building> buildings) {

        Vector<Square> sqBuildings = new Vector<Square>();
        for (Building localBuilding : buildings) {
            if (localBuilding.getType() == 0) {
                setVillageLevel(localBuilding.getLevel());
            }
            Square vv = new Square(new BuildingSquareType(localBuilding));
            vv.setPosition(new Point(localBuilding.getLocationX(), localBuilding.getLocationY()));
            sqBuildings.add(vv);

        }
        for (IBuildingListener listener : buildingListeners) {
            listener.updateBuildings(sqBuildings);
        }
    }
    /////////////////   Building Listeners ///////////
    //////////////////  BuildingType Listeners ////////////
    public void addBuildingTypeListener(IBuildingTypeListener listener) {

        buildingTypeListeners.add(listener);
    }

    public void removeBuildingTypeListener(IBuildingTypeListener listener) {

        buildingTypeListeners.remove(listener);
    }

    public void updateBuildingTypes(Vector<BuildingType> allTypes) {

        Vector<BuildingType> types = new Vector<BuildingType>();
        for (BuildingType buildingType : allTypes) {
            if (buildingType instanceof TownCenterBuildingType) {
            } else {
//                if(buildingType.getMinLevel()  )
                types.add(buildingType);
            }
        }
        for (IBuildingTypeListener listener : buildingTypeListeners) {
            listener.updateBuildingTypes(types);
        }
    }

    public void requestBuildingTypes() throws IOException {
        maiaclient.requestBuildingTypes();
    }
    //////////////////  BuildingType Listeners ////////////
    public boolean checkAvailableUsername(String sUsername) throws IOException {

        return maiaclient.checkAvailableUsername(sUsername);
    }

    public boolean checkAvailableVillageName(String sVillageName) throws IOException {
        return maiaclient.checkAvailableVillage(sVillageName);
    }

    public boolean loginUser(String username, char[] password) throws IOException {
        boolean loginResult = false;

        try {
            // We have to parse the char[] to a string
            // because .getText is outdated we have to user stringbuffer
            StringBuffer stb = new StringBuffer();
            for (char c : password) {
                stb.append(c);
            }
            String clearPass = stb.toString();
            String hashedPass = PassEncryptor.getSHAEncodedPassword(clearPass);

            this.user = maiaclient.loginUser(username, hashedPass);

            if (user != null) {
                loginResult = true;
            }

        } catch (ClassNotFoundException ex) {
        }
        return loginResult;
    }

    public boolean checkIfUserHasVillage(String username) throws IOException, ClassNotFoundException {

        this.village = maiaclient.fetchVillageOfUser(username);
        boolean hasVillage = false;

        if (village.getLocationX() != -1) {
            hasVillage = true;
        }
        return hasVillage;
    }

    /**
     * Fetches a user by a given username.
     * Returns null if the user was not found.
     * @param username
     * @return user
     */
    public User getUserByName(String username) throws IOException, ClassNotFoundException {

        User localUser = maiaclient.fetchUserByUsername(username);

        return localUser;
    }

    /**
     * Fetches all known villages.
     * @return villages
     */
    public Vector<Square> fetchInitializedVillages() throws IOException, ClassNotFoundException {

        Vector<Square> villages = new Vector<Square>();
        for (Village localVillage : maiaclient.fetchInitializedVillages()) {
            Square vv = new Square(new VillageSquareType(localVillage));
            vv.setPosition(new Point(localVillage.getLocationX(), localVillage.getLocationY()));
            villages.add(vv);
        }
        return villages;
    }

    /**
     * Registers a new user.
     * @param firstName
     * @param lastName
     * @param username
     * @param country
     * @param password
     * @param email
     * @throws java.io.IOException
     */
    public void registerUser(String lastName, String firstName, String username,
            char[] password, String email, String country) throws IOException {

        // Omzetten van character array naar String. 
        // Rechtstreeks .toString op char[] gebruiken geeft niet het gewenste resultaat
        // Daarom: stringbuffer gebruiken.
        StringBuffer stb = new StringBuffer();
        for (char c : password) {
            stb.append(c);
        }
        String clearPass = stb.toString();
        String hashedPass = PassEncryptor.getSHAEncodedPassword(clearPass);

        User newUser = new User(lastName, firstName, username, hashedPass, email, country, true);

        maiaclient.connectTo(getServerIP(), getServerPort());
        maiaclient.sendNewUser(newUser);

    }

    public User fetchUserByUserId(int userId) throws IOException, ClassNotFoundException {

        User localUser = maiaclient.fetchUserByUserId(userId);

        return localUser;
    }

    public Vector<BuildingType> fetchBuildingTypes() throws IOException, ClassNotFoundException {

        Vector<BuildingType> buildingTypes = maiaclient.fetchBuildingTypes();

        return buildingTypes;
    }

    /**
     * Creates a new village with a name, an owner, but no coordinates yet.
     * @param villageName
     * @param userId
     * @throws java.io.IOException 
     */
    public void createNewDummyVillage(String villageName, int userId) throws IOException {

        Village localvillage = new Village(villageName, userId, -1, -1);
        maiaclient.sendNewVillage(localvillage);
    }

    public void updateVillageLocation(Point location) throws IOException {

        maiaclient.updateVillageLocation(location, village.getVillageId());

    }

    public void assignDefaultResources() throws IOException {

        maiaclient.assignDefaultResources(village.getVillageId());

    }

    public void assignTownCenter() throws IOException {

        BuildingSquareType buildingSqTp = BuildingSquareTypeFactory.getInstance().makeBuilding("Town Center", new Point(5, 5));
        buildingSqTp.getBuilding().setVillageId(village.getVillageId());

        maiaclient.addBuilding(buildingSqTp.getBuilding());
    }

    public void addBuilding(Building building) throws IOException {

        building.setVillageId(village.getVillageId());
        maiaclient.addBuilding(building);
    }

    public void destructBuilding(int buildingId) throws IOException {

        maiaclient.destructBuilding(buildingId);

    }

    public void levelUpBuilding(Building building) throws IOException {

        maiaclient.levelUpBuilding(building);

    }

    public void editResources(Vector<Resource> resources) throws IOException {

        maiaclient.updateResources(resources);
    }

    public int getVillageLevel() {
        return villageLevel;
    }

    public void setVillageLevel(int villageLevel) {
        this.villageLevel = villageLevel;
    }
}
